package com.yunyao.common.web.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import com.yunyao.common.constant.Constants;
import com.yunyao.common.constant.enums.DateFormatPattern;
import com.yunyao.common.dto.AttachFileDto;
import com.yunyao.common.dto.FileDto;
import com.yunyao.common.dto.price.PriceDto;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.yunyao.common.constant.enums.DateFormatPattern.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;

/**
 * @Class：ConvertUtil
 * @Description： 操作工具类
 * @Author：chenyejian
 * @Date：Created in 2021/11/23 15:50
 */
public class ConvertUtil {

    private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");

    private ConvertUtil() {

    }

    /**
     * string null 转""
     * @param s 字符串
     * @return string null 转""
     */
    public static String null2String(String s) {
        return s == null ? "" : s;
    }

    /**
     * 字符串增加默认
     * @param s 字符串
     * @param a 默认值
     * @return 字符串增加默认值
     */
    public static String string2String(String s, String a) {
        return (s == null || Constants.EMPTY.equals(s.trim())) ? a : s;
    }

    /**
     * 对象转字符串
     * @param s 对象
     * @return 对象转字符串
     */
    public static String null2String(Object s) {
        return s == null ? "" : s.toString();
    }

    /**
     * 对象转int
     * @param v 对象
     * @return 对象转int
     */
    public static int getIntValue(Object v) {
        return getIntValue(v, -1);
    }

    /**
     * 对象转int
     * @param object 对象
     * @param defVal 默认值
     * @return 对象转int
     */
    public static int getIntValue(Object object, int defVal) {
        if (isEmpty(object)) {
            return defVal;
        }
        try {
            return (Integer.parseInt(object.toString()));
        } catch (NumberFormatException e) {
            return defVal;
        }
    }

    /**
     * 对象转long
     * @param v 对象
     * @return 对象转long
     */
    public static Long getLongValue(Object v) {
        return getLongValue(v, -1L);
    }

    /**
     * 对象转long
     * @param v 对象
     * @param def 默认值
     * @return 对象转long
     */
    public static Long getLongValue(Object v, Long def) {
        try {
            return Long.parseLong(null2String(v));
        } catch (Exception ex) {
            return def;
        }
    }

    /**
     * 对象转float
     * @param v 对象
     * @return 对象转float
     */
    public static Float getFloatValue(String v) {
        return getFloatValue(v, 0);
    }

    /**
     * 对象转float
     * @param v 对象
     * @param def 默认值
     * @return 对象转float
     */
    public static Float getFloatValue(String v, float def) {
        try {
            return Float.parseFloat(v);
        } catch (Exception ex) {
            return def;
        }
    }

    /**
     * 对象转double
     * @param v 对象
     * @return 对象转double
     */
    public static Double getDoubleValue(String v) {
        return getDoubleValue(v, 0);
    }

    public static Double getDoubleValue(BigDecimal v) {
        if(v == null){
            return 0d;
        }else{
            return v.doubleValue();
        }
    }

    /**
     * 对象转double
     * @param v 对象
     * @param def 默认值
     * @return 对象转double
     */
    public static Double getDoubleValue(String v, double def) {
        try {
            return Double.parseDouble(v);
        } catch (Exception ex) {
            return def;
        }
    }

    /**
     * 对象转double
     * @param v 对象
     * @return 对象转double
     */
    public static BigDecimal getBigDecimalValue(String v) {
        return getBigDecimalValue(v, BigDecimal.valueOf(0));
    }

    /**
     * 对象转double
     * @param v 对象
     * @param def 默认值
     * @return 对象转double
     */
    public static BigDecimal getBigDecimalValue(String v, BigDecimal def) {
        try {
            return new BigDecimal(v);
        } catch (Exception ex) {
            return def;
        }
    }

    public static BigDecimal getBigDecimalValue(BigDecimal v, BigDecimal def) {
        try {
            if (v == null) {
                return def;
            }
            return v;
        } catch (Exception ex) {
            return def;
        }
    }

    public static BigDecimal getBigDecimalValue(BigDecimal v) {
        return getBigDecimalValue(v, BigDecimal.ZERO);
    }

    /**
     * double相加
     * @param v1 参数1
     * @param v2 参数2
     * @return double相加
     */
    public static double doubleAdd(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * double相减
     * @param v1 参数1
     * @param v2 参数2
     * @return double相减
     */
    public static double doubleSub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 日期格式转换
     * @param v 日期
     * @return 日期格式转换
     */
    public static String getFormatDate(Date v) {
        return getFormatDate(v, false,"");
    }

    /**
     * 日期格式转换
     * @param v 日期
     * @param isNow 日期为空是是否默认当前时间
     * @return 日期格式转换
     */
    public static String getFormatDate(Date v,boolean isNow) {
        return getFormatDate(v,isNow, "");
    }

    /**
     * 日期格式转换
     * @param v 日期
     * @param isNow 日期为空时是否默认当前时间
     * @param format 格式
     * @return 日期格式转换
     */
    public static String getFormatDate(Date v, boolean isNow,String format) {
        try {
            if(v == null){
                if(isNow){
                    v = new Date();
                }else{
                    return  "";
                }
            }
            if (format == null || format.isEmpty()) {
                format = YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getPattern();
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            return simpleDateFormat.format(v);
        } catch (Exception ex) {
            return "";
        }
    }

    /**
     * 不够位数的在前面补0，保留num的长度位数字
     * @param code
     * @return
     */
    public static String autoGenericCode(String code, int num) {
        String result = "";
        // 保留num的位数
        // 0 代表前面补充0
        // num 代表长度为4
        // d 代表参数为正数型
        result = String.format("%0" + num + "d", Integer.parseInt(code));

        return result;
    }

    /**
     * 日期格式转换
     * @param v 日期
     * @param format 格式
     * @param isNow 日期为空是是否默认当前时间
     * @return 日期格式转换
     */
    public static String getFormatDateGMT(Date v, String format,boolean isNow) {
        try {
            if (v == null){
                if(isNow){
                    v = new Date();
                }else{
                    return  "";
                }
            }
            if (format == null || format.isEmpty()) {
                format = DateFormatPattern.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getPattern();
            }
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(v);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            return simpleDateFormat.format(calendar.getTime());
        } catch (Exception ex) {
            return "";
        }
    }

    public static String getFormatDateGMT(Date v, String format) {
        try {
            if (v == null) v = new Date();
            if (format == null || format.isEmpty()) format = DateFormatPattern.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getPattern();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(v);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format,Locale.ENGLISH);
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
            return simpleDateFormat.format(calendar.getTime());
        } catch (Exception ex) {
            return "";
        }
    }


    /**
     * 加千分位
     * @param args 参数
     * @return 加千分位
     */
    public static String milFloatFormat(String args) {
        String temp = args;
        String temp1 = "";
        if (!args.isEmpty()) {
            if (args.indexOf(Constants.POINT) == -1) {
                temp = args;
            } else {
                if (!Constants.EMPTY.equals(args.substring(0, args.indexOf(Constants.POINT)))) {
                    temp = args.substring(0, args.indexOf(Constants.POINT));
                } else {
                    temp = "0";
                }
                temp1 = args.substring(args.indexOf(Constants.POINT) + 1);
            }
            double d = getDoubleValue(temp);
            DecimalFormat df = new DecimalFormat("###,###");
            if (args.indexOf(Constants.POINT) == -1) {
                temp1 = "" + df.format(d);
            } else {
                temp1 = "" + df.format(d) + Constants.POINT + temp1;
            }
        }
        return temp1;
    }

    /**
     * jsonArray 转list
     * @param jsonArray array对象
     * @return jsonArray 转list
     */
    public static List<HashMap<String, Object>> handleJSONArray(JSONArray jsonArray) {
        List list = new ArrayList();
        for (Object object : jsonArray) {
            JSONObject jsonObject = (JSONObject) object;
            HashMap map = new HashMap<String, Object>(16);
            for (Map.Entry entry : jsonObject.entrySet()) {
                if (entry.getValue() instanceof JSONArray) {
                    map.put((String) entry.getKey(), handleJSONArray((JSONArray) entry.getValue()));
                } else {
                    map.put((String) entry.getKey(), entry.getValue());
                }
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 获取当前月第一天
     * @return 获取当前第一天
     */
    public static String getFirstDayOfMonth() {
        Calendar c = Calendar.getInstance();
        //设置为1号,当前日期既为本月第一天
        c.add(Calendar.MONTH, 0);
        c.set(Calendar.DAY_OF_MONTH, 1);
        return getFormatDate(c.getTime(), false,DateFormatPattern.YEAR_MONTH_DAY.getPattern());
    }

    /**
     * 获取当前月最后一天
     * @return 获取当前月最后一天
     */
    public static String getLastDayOfMonth() {
        Calendar ca = Calendar.getInstance();
        ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
        return getFormatDate(ca.getTime(), false,DateFormatPattern.YEAR_MONTH_DAY.getPattern());
    }

    /**
     * 计算两个日期之间相差的天数
     * @param smDate 较小的时间
     * @param bDate  较大的时间
     * @return 相差天数
     */
    public static Integer daysBetween(Date smDate, Date bDate) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DateFormatPattern.YEAR_MONTH_DAY.getPattern());
            smDate = sdf.parse(sdf.format(smDate));
            bDate = sdf.parse(sdf.format(bDate));
            Calendar cal = Calendar.getInstance();
            cal.setTime(smDate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(bDate);
            long time2 = cal.getTimeInMillis();
            long betweenDays= (time2 - time1) / (1000 * 3600 * 24);
            return Integer.parseInt(String.valueOf(betweenDays));
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 计算两个日期之间相差的分钟
     * @param smdate 较小的时间
     * @param bdate  较大的时间
     * @return 相差分钟
     */
    public static Integer minuteBetween(Date smdate, Date bdate) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(DateFormatPattern.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND.getPattern());
            smdate = sdf.parse(sdf.format(smdate));
            bdate = sdf.parse(sdf.format(bdate));
            Calendar cal = Calendar.getInstance();
            cal.setTime(smdate);
            long time1 = cal.getTimeInMillis();
            cal.setTime(bdate);
            long time2 = cal.getTimeInMillis();
            long betweenDays = (time2 - time1) / (1000 * 60);
            return Integer.parseInt(String.valueOf(betweenDays));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 计算两个日期之间相差
     * @param smdate 较小的时间
     * @param bdate  较大的时间
     * @return 相差时间
     */
    public static String dateBetween(Date smdate, Date bdate) {
        if(isEmpty(smdate)||isEmpty(bdate)){
            return "";
        }
        StringBuilder value = new StringBuilder();
        try {
            long diff = bdate.getTime() - smdate.getTime();
            long days = diff / (1000 * 60 * 60 * 24);
            long hours = (diff-days*(1000 * 60 * 60 * 24))/(1000* 60 * 60);
            long minutes = (diff-days*(1000 * 60 * 60 * 24)-hours*(1000* 60 * 60))/(1000* 60);
            long seconds = (diff-days*(1000 * 60 * 60 * 24)-hours*(1000* 60 * 60)-minutes*(1000 * 60))/1000;
            if(days>0){
                value.append(days+"天");
            }
            if(hours>0){
                value.append(hours+"小时");
            }
            if(minutes>0){
                value.append(minutes+"分");
            }
            if(seconds>0){
                value.append(seconds+"秒");
            }
            return value.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 比较两个日期大小 ，前者减后者
     * @param data 大日期
     * @param otherData 小日期
     * @return 比较两个日期大小 ，前者减后者
     */
    public static boolean  compareData(Date data, Date otherData) {
        try {
            Calendar cal = Calendar.getInstance();
            cal.setTime(data);
            long time1 = cal.getTimeInMillis();
            cal.setTime(otherData);
            long time2 = cal.getTimeInMillis();
            return (time1 - time2) > 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * string转日期格式
     * @param strDate 字符串
     * @return string转日期格式
     */
    public static Date getString2Date(String strDate) {
        return getString2Date(strDate, DateFormatPattern.YEAR_MONTH_DAY.getPattern());
    }

    /**
     * string转日期格式
     * @param strDate 字符串
     * @param format 日期格式
     * @return string转日期格式
     */
    public static Date getString2Date(String strDate, String format) {
        Date date = null;
        if (isEmpty(strDate)) {
            return null;
        }
        try {
            date = new SimpleDateFormat(format).parse(strDate);
        } catch (Exception e) {
            return null;
        }
        return date;
    }
    public static int getString2Integer(String strInteger) throws NumberFormatException {
        return Integer.parseInt(strInteger);
    }
    /**
     * @param date  – 日期
     * @param type  – 加减类型 y年m月d日
     * @param value – 加上的数值 如果为负数，则为减去
     * @return 返回增加后的Date
     */
    public static Date dateAdd(Date date, String type, int value) {
        try {
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            if (Constants.DATE_TYPE_DAY.equals(type)) {
                //日期加减N天
                cal.add(Calendar.DAY_OF_YEAR, value);
            } else if (Constants.DATE_TYPE_MONTH.equals(type)) {
                //日期加减N个月
                cal.add(Calendar.MONTH, value);
            } else if (Constants.DATE_TYPE_YEAR.equals(type)) {
                //日期加减N年
                cal.add(Calendar.YEAR, value);
            } else if (Constants.DATE_TYPE_HOUR.equals(type)) {
                //日期加减N小时
                cal.add(Calendar.HOUR, value);
            } else if (Constants.DATE_TYPE_MINUTE.equals(type)) {
                //日期加减N分钟
                cal.add(Calendar.MINUTE, value);
            }

            return cal.getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取指定日期的开始时间（当天的00:00:00）
     *
     * @param date 指定日期（注意：此处的date会被修改以反映开始时间）
     * @return 开始时间的Date对象
     */
    public static Date getStartOfDay(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的结束时间（当天的23:59:59）
     *
     * @param date 指定日期（注意：此处的date会被修改以反映结束时间的前一天，然后返回的是那一天的结束时间）
     * @return 结束时间的Date对象
     */
    public static Date getEndOfDay(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999); // 注意：这里设置为999毫秒，但通常数据库查询会包含整秒
        // 如果不需要修改原始date对象，可以创建一个新的Date对象来返回
        return calendar.getTime();
    }

    public static String replaceUTF8Bom(String str) {
        return str.replace("\uFEFF", "");
    }

    public static String toHtml(String s) {
        s = stringReplace(s, "<br>", "" + '\n');
        char[] c = s.toCharArray();
        char ch;
        int i = 0;
        StringBuffer buf = new StringBuffer();

        while (i < c.length) {
            ch = c[i++];
            if (ch == '\'') {
                buf.append("\''");
            }else if (ch == '<') {
                buf.append("&lt;");
            }else if (ch == '>') {
                buf.append("&gt;");
            }else if (ch == '"') {
                buf.append("&quot;");
            }else if (ch == '\n') {
                buf.append("<br>");
            }else {
                buf.append(ch);
            }
        }
        return buf.toString();
    }

    public static String stringReplace(String sou, String s1, String s2) {
        sou = null2String(sou);
        s1 = null2String(s1);
        s2 = null2String(s2);
        try {
            sou = sou.replace(s1, s2);
        } catch (Exception e) {
            System.out.println(e);
        }
        return sou;
    }

    /**
     * 判断字符串是否是数字
     * @param str 字符串
     * @return 判断字符串是否是数字
     */
    public static boolean isNumeric(String str) {
        Matcher isNum = NUMBER_PATTERN.matcher(str);
        return isNum.matches();
    }

    /**
     * 判断有无
     * @param value 字符串
     * @return 判断有无
     */
    public static String isHas(String value){
        String has = "无";
        if(Constants.STRING_ONE.equals(ConvertUtil.null2String(value))){
            has = "有";
        }
        if(Constants.STRING_TWO.equals(ConvertUtil.null2String(value))){
            has = "未知";
        }
        return has;
    }

    /**
     * 判断是否
     * @param value 字符串
     * @return 判断是否
     */
    public static  String isOrNot(String value){
        String val = "否";
        if(Constants.STRING_ONE.equals(ConvertUtil.null2String(value))){
            val = "是";
        }
        return val;
    }

    public static boolean isEmpty(Object object) {
        if (object == null) {
            return true;
        }
        if (Constants.EMPTY.equals(object)) {
            return true;
        }
        if(Constants.UNDEFINED.equals(object)){
            return true;
        }
        return Constants.NULL.equals(object);
    }

    public static boolean isNotEmpty(Object object) {
        return object != null && !Constants.EMPTY.equals(object) && !Constants.NULL.equals(object);
    }

    /**
     * 转换布尔值 1 true 0 false
     * @param flag 字符串
     * @return 转换布尔值 1 true 0 false
     */
    public static boolean getBoolean(String flag){
        return Constants.STRING_ONE.equals(flag);
    }

    /**
     * 将以逗号分隔的字符串转换成sql in查询的条件字符串
     * @param value 字符串
     * @return 将以逗号分隔的字符串转换成sql in查询的条件字符串
     */
    public static String getSqlCondition(String value){
        if(isNotEmpty(value)){
            //判断是否逗号结尾
            if(Constants.COMMA.equals(value.substring(value.length()-1,value.length()))){
                value = value.substring(0,value.length()-1);
            }
            value = value.replaceAll(",","','");
        }
        return null2String(value);
    }

    public static boolean isDouble(String str) {
        try {
            Double.parseDouble(str);
        } catch (Exception e) {
            return false;
        }
        return true;
    }


    /**
     * 判断是否是有效的JSON字符串,不为空返回true
     * @param json
     * @return
     */
    public static boolean isValidNotEmptyJson(String json) {
        try {
            if (StringUtils.isEmpty(json)){
                return false;
            }
            // 尝试将字符串解析为JSONObject或JSONArray
            // 如果json是一个JSON对象或数组，这个调用将不会抛出异常
            JSON.parse(json);
            return true;
        } catch (JSONException e) {
            // 如果解析失败，抛出JSONException，则字符串不是有效的JSON
            return false;
        }
    }

    /**
     * 判断是否是有效的JSON字符串，为空返回true
     * @param json
     * @return
     */
    public static boolean isValidEmptyJson(String json) {
        return !isValidNotEmptyJson(json);
    }

    public static AttachFileDto fileDto2AttachDto(FileDto fileDto){
        return new AttachFileDto(fileDto.getFileOriginName(), fileDto.getFileUrl());
    }

    public static FileDto attachDto2FileDto(AttachFileDto attachFileDto){
        return new FileDto(attachFileDto.getName(), attachFileDto.getUrl());
    }


    /**
     * 统一文件格式
     * @param fileString
     * @return
     */
    public static List<FileDto> getFileDtoList(String fileString){
        if (StringUtils.isEmpty(fileString)){
            return new ArrayList<>();
        }
        List<FileDto> fileDtoList = new ArrayList<>();
        try {
            fileDtoList = JSONArray.parseArray(fileString, FileDto.class);
            if (CollectionUtils.isNotEmpty(fileDtoList)){
                FileDto fileDto = fileDtoList.get(0);
                if (StringUtils.isEmpty(fileDto.getFileOriginName()) && StringUtils.isEmpty(fileDto.getFileUrl())){
                    List<AttachFileDto> attachFileDtoList = JSONArray.parseArray(fileString, AttachFileDto.class);
                    fileDtoList = attachFileDtoList.stream().map(attachFileDto -> attachDto2FileDto(attachFileDto)).collect(Collectors.toList());
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            return new ArrayList<>();
        }
        return fileDtoList;
    }


    /**
     * 含税总价转 含税单价和不含税单价
     * @param includingTaxTotalPrice 含税总价
     * @param quantity 数量
     * @param tax 税率
     * @return
     */
    public static PriceDto convertTaxTotal2UnitPrice(BigDecimal includingTaxTotalPrice, BigDecimal quantity, BigDecimal tax){
        PriceDto priceDto = new PriceDto();
        if (Objects.nonNull(includingTaxTotalPrice) && Objects.nonNull(quantity) && Objects.nonNull(tax) && quantity.compareTo(BigDecimal.ZERO) > 0) {
            BigDecimal includingTaxUnitPrice = includingTaxTotalPrice.divide(quantity,
                    4, RoundingMode.HALF_UP);
            /**
             * 含税单价 = 不含税单价 * (1 + 税率)
             * 不含税单价 = 含税单价/(1 + 税率)
             */
            BigDecimal taxPrecent = tax.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            priceDto.setExcludingTaxUnitPrice(includingTaxUnitPrice.divide(BigDecimal.valueOf(1).add(taxPrecent), 4, RoundingMode.HALF_UP));
            priceDto.setIncludingTaxUnitPrice(includingTaxUnitPrice);
        }
        return priceDto;
    }
}
